package com.yuqingxin.redisCacheApi.common.redisCache;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yuqingxin.redisCacheApi.entity.ApiScheduleEntity;
import com.yuqingxin.redisCacheApi.mapper.ApiScheduleMapper;
import com.yuqingxin.redisCacheApi.util.ArgumentsUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledFuture;


/**
 * @author yuqingxin
 * */
@Log4j2
@Service
public class ApiActiveService {

    //超时时间
    private final Integer timeout = 60*60*24*3;

    @Autowired
    private ApiScheduleMapper apiScheduleMapper;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Autowired
    private Executor threadPool;

    @Autowired
    private Map<String, ScheduledFuture<?>> scheduledFutureMap;

    @Autowired
    private ArgumentsUtil argumentsUtil;

    /**
     * 获取需要更新的Api
     * */
    public List<ApiScheduleEntity> getApiScheduleList(){
        LambdaQueryWrapper<ApiScheduleEntity> aL =  new LambdaQueryWrapper<>();
        aL.eq(ApiScheduleEntity::getStatus,1);
        return apiScheduleMapper.selectList(aL);
    }

    /**
     * 获取长时间未使用的Api
     * @param timeout 多长时间未使用  秒
     * */
    public List<ApiScheduleEntity> getLongTimeUnUseApiList(Integer timeout){
        LambdaQueryWrapper<ApiScheduleEntity> aL =  new LambdaQueryWrapper<>();
        aL.eq(ApiScheduleEntity::getStatus,1)
                .le(ApiScheduleEntity::getLastActiveTime, LocalDateTime.now().minusSeconds(timeout));
        return apiScheduleMapper.selectList(aL);
    }

    /**
     * 调用单个Api方法
     * */
    public void runApiMethod(ApiScheduleEntity apiSchedule){
        // 类名
        String className = apiSchedule.getClassName();
        // 方法名
        String methodName = apiSchedule.getMethodName();
        // 参数值
        String argumentsString = apiSchedule.getArguments();

        // 参数类型
        String argumentsType = apiSchedule.getArgumentsType();
        Class<?>[] parameterTypes = argumentsUtil.getClassArray(argumentsType);
        Object[] arguments = argumentsUtil.getObjectArray(argumentsString,parameterTypes);
        try {
            // 获取类对象
            Class<?> apiClass = Class.forName(className);
            // 获取方法对象
            Method method = apiClass.getMethod(methodName, parameterTypes);
            // 获取该类的Bean对象
            Object instance = applicationContext.getBean(apiClass);
            // 调用方法
            Object result = method.invoke(instance, arguments);
            // 处理方法返回值
            log.info("Result: " + result);
        } catch (Exception e) {
            log.error("RunApiMethod Error: {}：{}::{}",className,methodName,argumentsString);
            e.printStackTrace();
        }
    }


    /**
     * 批量调用需要更新缓存的Api
     * */
    public Boolean runApiMethodList(){
        List<ApiScheduleEntity> list = getApiScheduleList();
        for (ApiScheduleEntity api : list) {
            threadPool.execute(()->{
                runApiMethod(api);
            });
        }
        return true;
    }

    /**
     * 添加单个Api定时任务
     * */
    public void addApiScheduledTask(ApiScheduleEntity apiSchedule){
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                runApiMethod(apiSchedule);
            }
        };
        ScheduledFuture<?> scheduledFuture =  threadPoolTaskScheduler.schedule(timerTask,new CronTrigger(apiSchedule.getCron()));
        //将该实例存入到缓存map中
        if (null != scheduledFuture){
            String key = apiSchedule.getClassName() + ":" + apiSchedule.getMethodName()+ ":" +apiSchedule.getArguments();
            log.info("Add ApiScheduledTask:{}",key);
            scheduledFutureMap.put(key,scheduledFuture);
        }
    }

    /**
     * 批量取消长时间未被主动调用的Api定时更新任务
     * */
    public void cancelApiScheduleTaskList(){
        List<ApiScheduleEntity> list = getLongTimeUnUseApiList(timeout);
        for (ApiScheduleEntity apiSchedule : list) {
            threadPool.execute(()->{
                //去除对应定时认为
                String key = apiSchedule.getClassName() + ":" +apiSchedule.getMethodName() + ":" + apiSchedule.getArguments();
                ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(key);
                if (null != scheduledFuture){
                    scheduledFuture.cancel(true);
                    scheduledFutureMap.remove(key);
                }
                //更新数据库状态
                apiSchedule.setStatus(0);
                apiScheduleMapper.updateById(apiSchedule);
            });
        }
    }

    /**
     * 删除单个Api定时任务
     * */
    public void removeApiScheduledTask(ApiScheduleEntity apiSchedule){
        if (null != apiSchedule){
            String key = apiSchedule.getClassName() + ":" + apiSchedule.getMethodName()+ ":" +apiSchedule.getArguments();
            ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(key);
            if (null != scheduledFuture){
                scheduledFuture.cancel(true);
                log.info("Remove ApiScheduledTask:{}",key);
                scheduledFutureMap.remove(key);
            }
        }
    }

    /**
     * 更新单个Api定时任务
     * */
    public void updateApiScheduledTask(ApiScheduleEntity apiSchedule){
        if (null != apiSchedule){
            removeApiScheduledTask(apiSchedule);
            addApiScheduledTask(apiSchedule);
        }
    }

    /**
     * 初始化时-添加单个Api定时任务
     * */
    public void initAddApiScheduledTask(ApiScheduleEntity apiSchedule) throws Exception{
        //先运行一次
        runApiMethod(apiSchedule);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                runApiMethod(apiSchedule);
            }
        };
        // 获取类对象
        Class<?> apiClass = Class.forName(apiSchedule.getClassName());
        // 获取方法对象
        Method method = apiClass.getMethod(apiSchedule.getMethodName(), argumentsUtil.getClassArray(apiSchedule.getArgumentsType()));
        RedisCache redisCache = method.getAnnotation(RedisCache.class);
        ScheduledFuture<?> scheduledFuture =  threadPoolTaskScheduler.schedule(timerTask,new CronTrigger(redisCache.cron()));
        //将该实例存入到缓存map中
        if (null != scheduledFuture){
            String key = apiSchedule.getClassName() + ":" + apiSchedule.getMethodName()+ ":" +apiSchedule.getArguments();
            log.info("Init Add ApiScheduledTask:{}",key);
            scheduledFutureMap.put(key,scheduledFuture);
        }
    }
}
